﻿using Colorful.Furniture.CommonDto;
using Colorful.Furniture.Extensions;
using FreeSql;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Services;
using Volo.Abp.Guids;

namespace Colorful.Furniture.EnterpriseManagement;

/// <summary>
///  部门服务
/// </summary>
public class DepartmentAppService : ApplicationService
{
    private readonly IBaseRepository<Department> _departmentRepository;
    private readonly IGuidGenerator _guidGenerator;
    private readonly IFreeSql _freeSql;
    private readonly ILogger<DepartmentAppService> _logger;
    private const int SortMax = 100000000;
    private const int SortStep = 1000;

    public DepartmentAppService(
        IBaseRepository<Department> departmentRepository,
        IGuidGenerator guidGenerator,
        IFreeSql freeSql,
        ILogger<DepartmentAppService> logger)
    {
        _departmentRepository = departmentRepository;
        _guidGenerator = guidGenerator;
        _freeSql = freeSql;
        _logger = logger;
    }

    /// <summary>
    ///  获取树形
    /// </summary>
    /// <returns></returns>
    public async Task<List<TreeOutputDto<long>>> GetTreeAsync()
    {
        var departmentAllList = await _departmentRepository
            .Where(x => x.Id != Guid.Empty)
            .ToListAsync();

        var treeList = await RecursionTreeAsync(departmentAllList, 0);

        return treeList;
    }

    /// <summary>
    ///  递归获取树列表
    /// </summary>
    /// <returns></returns>
    private static async Task<List<TreeOutputDto<long>>> RecursionTreeAsync(IList<Department> allDepartments, long parentDepartId)
    {
        //按照顺序查询下级的部门列表
        var childrenDepartments = allDepartments
            .Where(x => x.ParentDepartId == parentDepartId)
            .OrderByDescending(x => x.Sort);

        var treeOutputs = new List<TreeOutputDto<long>>();

        foreach (var childrenDepartment in childrenDepartments)
        {
            treeOutputs.Add(new TreeOutputDto<long>
            {
                Label = childrenDepartment.Name,
                Id = childrenDepartment.DepartId,
                ExpandParams = new Dictionary<string, object>
                {
                    {"dep_id",childrenDepartment.Id},
                    {"leader",childrenDepartment.DepartmentLeader.StringToGeneric<List<string>>()}
                },
                Children = await RecursionTreeAsync(allDepartments, childrenDepartment.DepartId)
            });
        }

        return treeOutputs;
    }


    /// <summary>
    ///  获取级联选项
    /// </summary>
    /// <returns></returns>
    public async Task<List<CascadeOptionOutputDto<object, long>>> GetCascadeOptionAsync(bool isUseDepart = false)
    {
        var departmentAllList = await _departmentRepository
            .Where(x => x.Id != Guid.Empty)
            .ToListAsync();

        var treeList = await RecursionCascadeOptionAsync(departmentAllList, 1, isUseDepart);

        return treeList;
    }

    /// <summary>
    ///  递归获取树列表
    /// </summary>
    /// <returns></returns>
    private static async Task<List<CascadeOptionOutputDto<object, long>>> RecursionCascadeOptionAsync(IList<Department> allDepartments, long parentDepartId, bool isUseDepartId)
    {
        //按照顺序查询下级的部门列表
        var childrenDepartments = allDepartments
            .Where(x => x.ParentDepartId == parentDepartId)
            .OrderByDescending(x => x.Sort);

        var optionOutputDtos = new List<CascadeOptionOutputDto<object, long>>();

        foreach (var childrenDepartment in childrenDepartments)
        {
            var optionItem = new CascadeOptionOutputDto<object, long>
            {
                Label = childrenDepartment.Name,
                Value = isUseDepartId ? childrenDepartment.DepartId : childrenDepartment.Id,
                Data = childrenDepartment.DepartId
            };

            var children = await RecursionCascadeOptionAsync(allDepartments, childrenDepartment.DepartId, isUseDepartId);

            if (children.Any())
                optionItem.Children = children;

            optionOutputDtos.Add(optionItem);
        }

        return optionOutputDtos;
    }

    /// <summary>
    /// 创建
    /// </summary>
    /// <returns></returns>
    public async Task<bool> CreateAsync([FromBody] CreateDepartmentInputDto departmentInput)
    {
        if (departmentInput.ParentDepartId == 0 || !departmentInput.ParentDepartId.HasValue)
            throw new UserFriendlyException("请选择需要添加子级的父级部门");

        //查询上级部门信息
        var parentDepart = await _departmentRepository
            .Where(x => x.DepartId == departmentInput.ParentDepartId)
            .ToOneAsync();
        if (parentDepart == null)
            throw new UserFriendlyException("父级部门不存在或被管理员删除");

        // 获得最大code值
        var organizationMaxInfo = await _freeSql.Select<Department>()
            .OrderByDescending(x => x.DepartId)
            .FirstAsync(x => new
            {
                x.DepartId
            });

        //写入数据库
        await _departmentRepository.InsertAsync(new Department
        {
            Id = _guidGenerator.Create(),
            DepartId = organizationMaxInfo.DepartId + 1,
            Name = departmentInput.Name,
            NameEn = departmentInput.NameEn,
            ClassId = $"{parentDepart.ClassId}{organizationMaxInfo.DepartId + 1},", //赋值层级代码
            ParentDepartId = departmentInput.ParentDepartId.Value,
            AddTime = DateTime.Now,
            Sort = 1
        });

        return true;
        
    }

    /// <summary>
    ///  部门详情
    /// </summary>
    /// <param name="id">部门编码</param>
    /// <returns></returns>
    public async Task<DepartmentDetailOutputDto> GetDetailAsync(Guid id)
    {
        var model = await _departmentRepository
            .Where(x => x.Id == id)
            .ToOneAsync(x => new DepartmentDetailOutputDto());

        if (model == null)
            throw new UserFriendlyException("部门不存在或背管理员删除");

        return model;
    }

    /// <summary>
    ///  设置负责人
    /// </summary>
    /// <returns></returns>
    public async Task<bool> SetLeaderAsync([FromBody] SetLeaderInputDto input)
    {
        var depart = new Department { DepartId = input.DepartId };

        _departmentRepository.Attach(depart);
        depart.DepartmentLeader = input.Leaders != null && input.Leaders.Any()
            ? input.Leaders.GenericToString()
            : string.Empty;

        var result = await _departmentRepository.UpdateAsync(depart);

        return result > 0;
    }
    
    /// <summary>
    ///   更新
    /// </summary>
    /// <param name="departmentInput">请求体</param>
    /// <returns></returns>
    public async Task<bool> UpdateAsync([FromBody] UpdateDepartmentInputDto departmentInput)
    {
        var departmentDbId = await _departmentRepository
            .Where(x => x.DepartId == departmentInput.DepartId)
            .ToOneAsync(x => x.Id);

        if (departmentDbId == Guid.Empty)
            throw new UserFriendlyException("未能找到部门数据");
        
        //父级的层级
        var parentClassId = string.Empty;
        if (departmentInput.ParentDepartId.HasValue)
        {
            //获取父级部门信息
            var parentDepart = await _departmentRepository
                .Where(x => x.DepartId == departmentInput.ParentDepartId)
                .ToOneAsync(x => new
                {
                    x.DepartId,
                    x.ClassId,
                    x.Id
                });
            parentClassId = parentDepart.ClassId;
            
            //更新父级的排序
            var departParentUpdate = new Department { Id = parentDepart.Id };
            _departmentRepository.Attach(departParentUpdate);
            //departParentUpdate.Sort = result2.Department.DepartmentOrder;
            await _departmentRepository.UpdateAsync(departParentUpdate);
        }

        //更新当前部门的信息
        var depart = new Department { Id = departmentDbId };
        _departmentRepository.Attach(depart);

        depart.Name = departmentInput.Name;
        depart.NameEn = departmentInput.NameEn;
        //depart.Sort = result1.Department.DepartmentOrder;

        if (departmentInput.ParentDepartId.HasValue)
        {
            depart.ClassId = $"{parentClassId},{departmentInput.DepartId},"; //赋值层级代码

            depart.ParentDepartId = departmentInput.ParentDepartId.Value;
        }

        var updateResult = await _departmentRepository.UpdateAsync(depart);

        return updateResult > 0;
    }

    /// <summary>
    ///  拖拽排序
    /// </summary>
    /// <returns></returns>
    public async Task<bool> DragAsync([FromBody] DragDepartmentInputDto departmentInput)
    {
        using var untOfWork = _freeSql.CreateUnitOfWork();
        _departmentRepository.UnitOfWork = untOfWork;

        var dragNode = await _departmentRepository
            .Where(x => x.DepartId == departmentInput.Id)
            .ToOneAsync(x => new
            {
                x.Id,
                x.DepartId,
                x.ParentDepartId,
            });

        if (dragNode == null)
            throw new UserFriendlyException("拖拽部门节点不存在");

        var draggedNode = await _freeSql.Select<Department, Department>()
            .LeftJoin((a, b) => a.ParentDepartId == b.DepartId)
            .Where((a, b) => a.DepartId == departmentInput.DraggedId)
            .ToOneAsync((a, b) => new
            {
                a.Id,
                a.DepartId,
                a.ParentDepartId,
                a.ClassId,
                ParentDepartClassId = b.ClassId
            });

        if (draggedNode == null)
            throw new UserFriendlyException("拖拽后放置的部门节点不存在");

        switch (departmentInput.DragType)
        {
            //放在节点之前
            case "before":
            //放在节点之后
            case "after":

                //查询当前拖拽后节点当前兄弟节点数据
                var draggedParentChildrenDepartments =
                    await _departmentRepository
                        .Where(x => x.ParentDepartId == draggedNode.ParentDepartId)
                        .ToListAsync(x => new DepartmentOutputDto1
                        {
                            Id = x.Id,
                            DepartId = x.DepartId
                        });

                //删除满足条件的节点
                var findIndex = draggedParentChildrenDepartments.FindIndex(x => x.Id == dragNode.Id);
                if (findIndex > -1)
                    draggedParentChildrenDepartments.RemoveAt(findIndex);

                //根据拖拽的来调整list节点的数据
                switch (departmentInput.DragType)
                {
                    case "before":
                        draggedParentChildrenDepartments.InsertBefore(x => x.Id == draggedNode.Id, new DepartmentOutputDto1 { Id = dragNode.Id, DepartId = dragNode.DepartId });
                        break;
                    case "after":
                        draggedParentChildrenDepartments.InsertAfter(x => x.Id == draggedNode.Id, new DepartmentOutputDto1 { Id = dragNode.Id, DepartId = dragNode.DepartId });
                        break;
                }

                //重新排序
                var index = 0;
                var sortOutputDtos = draggedParentChildrenDepartments.Select(x =>
                  {
                      var departmentSortOutputDto = new DepartmentSortOutputDto
                      {
                          Id = x.Id,
                          DepartId = x.DepartId,
                          Sort = SortMax - index * SortStep
                      };

                      index++;

                      return departmentSortOutputDto;
                  });

                //更新部门列表数据
                var updateList = new List<Department>();
                foreach (var departmentSortOutputDto in sortOutputDtos)
                {
                    var department = new Department { Id = departmentSortOutputDto.Id };
                    _departmentRepository.Attach(department);
                    department.Sort = departmentSortOutputDto.Sort;

                    //拖拽到某个节点内部里
                    if (departmentSortOutputDto.Id == dragNode.Id &&
                        dragNode.ParentDepartId != draggedNode.ParentDepartId)
                    {
                        department.ParentDepartId = draggedNode.ParentDepartId;
                        department.ClassId = $"{draggedNode.ParentDepartClassId}{dragNode.DepartId},";
                        }
                    

                    updateList.Add(department);
                }

                if (updateList.Any())
                    await _departmentRepository.UpdateAsync(updateList);

                break;

            //放在节点内
            case "inner":

                var update2 = new Department { Id = dragNode.Id };
                _departmentRepository.Attach(update2);
                update2.ParentDepartId = draggedNode.DepartId;
                update2.ClassId = $"{draggedNode.ClassId}{dragNode.DepartId},";
                update2.Sort = SortMax;

                await _departmentRepository.UpdateAsync(update2);
                
                break;
        }

        //判断拖拽的当前节点的父节点下面是否只有一个节点
        var dragParentHasChildren = await _departmentRepository
            .Where(x => x.ParentDepartId == dragNode.ParentDepartId)
            .ToListAsync(x => new
            {
                x.Id,
                x.DepartId
            });

        if (dragParentHasChildren.Count == 1)
        {
            //第一条即最后一条数据
            var firstNode = dragParentHasChildren.First();

            var update3 = new Department { Id = firstNode.Id };
            _departmentRepository.Attach(update3);
            update3.Sort = SortMax;

            await _departmentRepository.UpdateAsync(update3);
            
        }

        untOfWork.Commit();

        return true;
    }

    /// <summary>
    ///  删除
    /// </summary>
    /// <param name="id">部门id</param>
    /// <returns></returns>
    public async Task<bool> DeleteAsync(long id)
    {
        var exeResult = await _departmentRepository.DeleteAsync(x => x.DepartId == id);

        _logger.LogInformation($"删除机构数据:{id} {exeResult} 条");

        return exeResult > 0;
    }

    /// <summary>
    ///  获取部门选项列表
    /// </summary>
    /// <returns></returns>
    public async Task<List<OptionOutputDto<long, Guid>>> GetOptionListAsync()
    {
        var departmentList = await _departmentRepository.Where(x => x.Id != Guid.Empty)
            .ToListAsync(x => new OptionOutputDto<long, Guid>
            {
                Label = x.Name,
                Value = x.DepartId,
                Data = x.Id
            });

        return departmentList;
    }
}